package org.zlb.netty.server.rpc;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;

import org.zlb.netty.dbo.RpcRequest;
import org.zlb.netty.dbo.RpcResponse;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import net.sf.cglib.reflect.FastClass;
import net.sf.cglib.reflect.FastMethod;

public class RpcMessageServerHandler extends ChannelInboundHandlerAdapter {
    
    private int heartBeat = 0;
    private Map<String, Object> serviceMap;
    
    public RpcMessageServerHandler(Map<String, Object> serviceMap) {
        this.serviceMap = serviceMap;
    }
    
   
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        heartBeat = 0;
        
        RpcRequest req = (RpcRequest)msg;
        System.out.println(req);
        RpcResponse resp = handle(req);
        
        ctx.writeAndFlush(resp);
    }
    
    private RpcResponse handle(RpcRequest req) {
        Object obj = serviceMap.get(req.getClassName());
        
        String requestId = req.getRequestId();
        FastClass fastClass = FastClass.create(obj.getClass());
        FastMethod fastMethod = fastClass.getMethod(req.getMethodName(), req.getParamTypes());
        Object result;
        RpcResponse resp = new RpcResponse();
        resp.setRequestId(requestId);
        try {
            result = fastMethod.invoke(obj, req.getArguments());
            resp.setResult(result);
        } catch (InvocationTargetException e) {
             e.printStackTrace();
             resp.setThrowable(e);
        }
        
        return resp;
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
    
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleState state = ((IdleStateEvent) evt).state();
            if (state == IdleState.READER_IDLE) {
                if (heartBeat >= 3) {
                    ctx.disconnect();
                    System.out.println("与远端地址" + ctx.channel().remoteAddress() + "断开连接！");
                } else {
                    heartBeat ++;
                    System.out.println("丢失第" + heartBeat + "个心跳包");
                }
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }
}
